package com.exposit.smarthouse.system.impl;

import com.exposit.smarthouse.system.*;
import com.exposit.smarthouse.environment.*;
import com.exposit.smarthouse.environment.impl.*;
import com.exposit.smarthouse.model.*;
import com.exposit.smarthouse.sensor.impl.*;
import com.exposit.smarthouse.state.*;
import com.exposit.smarthouse.state.impl.*;
import com.exposit.smarthouse.utils.*;
import org.apache.log4j.*;

import java.util.concurrent.*;


public class GardenControlSystemImpl implements GardenControlSystem
{
    private static final Logger LOG = Logger.getLogger("GardenControlSystem");

    private GardenEnvironment gardenEnvironment = new GardenEnvironmentImpl();

    private ConcurrentLinkedQueue<ISensor> iSensors = new ConcurrentLinkedQueue<ISensor>();

    private ConcurrentHashMap<String, Double> controlParams = new ConcurrentHashMap<String, Double>();

    public GardenControlSystemImpl()
    {
        //add states in environment
        gardenEnvironment.addState(new LuminosityStateImpl(StartEnvironment.getLuminosity()));
        gardenEnvironment.addState(new SoilHumidityStateImpl(StartEnvironment.getSolidHumidity()));

        //add sensor
        iSensors.add(new LuminositySensorImpl());
        iSensors.add(new SoilHumiditySensorImpl());

        //set system controlParams
        controlParams.put(LuminosityState.TYPE + "MIN", 0.5);
        controlParams.put(LuminosityState.TYPE + "MAX", 1.0);
        controlParams.put(SoilHumidityState.TYPE + "MAX", 1.0);
        controlParams.put(SoilHumidityState.TYPE + "MIN", 0.3);
    }

    @Override
    public void setEnvironment(GardenEnvironment environment)
    {
        this.gardenEnvironment = environment;
    }

    @Override
    public GardenEnvironment getEnvironment()
    {
        return gardenEnvironment;
    }

    @Override
    public void addSensor(ISensor sensor)
    {
        this.iSensors.add(sensor);
    }

    @Override
    public ConcurrentLinkedQueue<ISensor> getSensors()
    {
        return iSensors;
    }

    @Override
    public void start()
    {
        try
        {
            LOG.info("GET SENSORS STATE");
            getSensorState();
            Thread.sleep(3000);

            LOG.info("CHANGE STATES");
            changeState();

            Thread.sleep(3000);
            LOG.info("GET SENSORS STATE");
            getSensorState();

        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    private void getSensorState()
    {
        for(ISensor iSensor: iSensors)
        {
            Double min = controlParams.get(iSensor.getType() + "MIN");
            Double max = controlParams.get(iSensor.getType() + "MAX");

            iSensor.setState(gardenEnvironment.getStates().get(iSensor.getType()));
            LOG.info("SENSOR BY " + iSensor.getType() + " TYPE HAVE VALUE " + iSensor.getState().getValue());

            if(iSensor.getValue() < min)
            {
                iSensor.getState().setValue((max + min)/2);
                LOG.info("SYSTEM CHANGE STATE " + iSensor.getType() + " TYPE ON VALUE " + iSensor.getState().getValue());
            }
        }
    }


    private void changeState()
    {
        ConcurrentMap<String, IState> iStates = gardenEnvironment.getStates();

        for(String identifier: gardenEnvironment.getStates().keySet())
        {
            IState iState = iStates.get(identifier);
            LOG.info("STATE BY " + iState.getType() + " TYPE HAVE VALUE BEFORE UPDATE " + iState.getValue());

            iState.setValue(StartEnvironment.randomValue(iState));

            LOG.info("STATE BY " + iState.getType() + " TYPE HAVE VALUE AFTER UPDATE " + iState.getValue());
            iStates.replace(identifier, iState);
        }
    }
}
